package com.wyj.utils

import androidx.arch.core.executor.ArchTaskExecutor
import androidx.databinding.ObservableField
import androidx.lifecycle.MutableLiveData

interface MMKVProp<T> {
    fun set(value: T?)
    fun get(): T?
    fun delete()
    fun setMMKVValue(value: T?)
    fun getMMKVValue(): T?
}

class Prop<T>(private val builder: PropBuilder<T>) : MMKVProp<T> {
    val onPropChangedCallback = ArrayList<Consumer<Any?>>()

    @Synchronized
    override fun set(value: T?) {
        onPropChangedCallback.forEach {
            it.accept(value)
        }
        builder.set(value)
    }

    @Synchronized
    override fun get(): T? = builder.get()

    @Synchronized
    override fun delete() = builder.delete()

    @Synchronized
    override fun getMMKVValue(): T? = builder.getMMKVValue()

    @Synchronized
    override fun setMMKVValue(value: T?) = builder.setMMKVValue(value)
    fun asLiveData(): MutableLiveData<T> = object : MutableLiveData<T>(get()) {
        init {
            onPropChangedCallback.add { v ->
                if (ArchTaskExecutor.getInstance().isMainThread) {
                    super.setValue(v as? T)
                } else {
                    super.postValue(v as? T)
                }
            }
        }

        @Synchronized
        override fun getValue(): T? = super.getValue() ?: this@Prop.get()

        @Synchronized
        override fun setValue(value: T) {
            super.setValue(value)
            this@Prop.set(value)
        }
    }

    fun asObservableField(): ObservableField<T> = object : ObservableField<T>(get()) {
        init {
            onPropChangedCallback.add { v ->
                super.set(v as? T)
            }
        }

        @Synchronized
        override fun get(): T? = super.get() ?: this@Prop.get()

        @Synchronized
        override fun set(value: T) {
            super.set(value)
            this@Prop.set(value)
        }
    }

    abstract class PropBuilder<T>(key: String) : MMKVProp<T> {
        val propEasy = PropEasy(key)
        abstract override fun set(value: T?)
        abstract override fun get(): T?
        abstract override fun getMMKVValue(): T?
        abstract override fun setMMKVValue(value: T?)
        override fun delete() = propEasy.delete()
    }

    class StringBuilder(key: String) : PropBuilder<String>(key) {
        @Synchronized
        override fun set(value: String?) = propEasy.set(value)

        @Synchronized
        override fun get(): String? = propEasy.get()

        @Synchronized
        override fun getMMKVValue(): String? = propEasy.getMMKVValue()

        @Synchronized
        override fun setMMKVValue(value: String?) = propEasy.setMMKVValue(value)

    }

    class BooleanBuilder(key: String) : PropBuilder<Boolean>(key) {
        @Synchronized
        override fun set(value: Boolean?) = propEasy.set(value)

        @Synchronized
        override fun get(): Boolean? = propEasy.get()

        @Synchronized
        override fun getMMKVValue(): Boolean? = propEasy.getMMKVValue()

        @Synchronized
        override fun setMMKVValue(value: Boolean?) = propEasy.setMMKVValue(value)
    }

    class IntBuilder(key: String) : PropBuilder<Int>(key) {
        @Synchronized
        override fun set(value: Int?) = propEasy.set(value)

        @Synchronized
        override fun get(): Int? = propEasy.get()

        @Synchronized
        override fun getMMKVValue(): Int? = propEasy.getMMKVValue()

        @Synchronized
        override fun setMMKVValue(value: Int?) = propEasy.setMMKVValue(value)
    }
}